package com.czy.workflow.core.executor;

import com.czy.workflow.core.exception.FlowException;
import com.czy.workflow.core.exception.FlowOperationTypeInvalidException;
import com.czy.workflow.core.model.*;
import com.czy.workflow.core.selector.NodeBranchSelector;
import com.czy.workflow.core.selector.NodeBranchSelectorFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

public class SimpleTaskExecutor extends AbstractTaskExecutor {

    List<OperationType> autoTypes = Arrays.asList(OperationType.START, OperationType.AUTO, OperationType.END);


    @Override
    public boolean startTask(TaskInfo taskInfo)  throws FlowException {
        //为避免脏数据的影响，先清理文档的运行时节点
        flowContext.getFlowService().clearCurrentNodes(taskInfo.getDocId());

        FlowMain flowMain = flowContext.getFlowService().getFlowMainById(taskInfo.getFlowId());
        taskInfo.setFlowCode(flowMain.getCode());
        this.setTaskInfo(taskInfo);
        List<FlowNode> nodes = flowContext.getFlowService().getStartNodes(taskInfo.getFlowId());
        for(FlowNode node : nodes){
            taskInfo.setNode(node);
            if(flowContext.getFlowConfig().isMultiThread()) {
                this.setTaskInfo(taskInfo);
                flowContext.getThreadPoolService().execute(this);
            }else{
                this.execute(taskInfo);
            }
        }

        return true;
    }

    @Override
    public boolean finishTask(TaskInfo taskInfo) {

        //清理临时缓存节点
        flowContext.getFlowService().clearCurrentNodes(taskInfo.getDocId());

        logger.info(String.format("Task [%s] is finished", taskInfo.getDocId()));

        return true;
    }


    /**
     * 自动化执行
     * @param taskInfo
     * @param nextNodes
     * @throws FlowException
     */
    public void autoExecute(TaskInfo taskInfo, List<FlowNode> nextNodes) throws FlowException {

        //更新运行时节点信息
        //删除当前节点->写入后续节点
        flowContext.getFlowService().refreshCurrentNodes(taskInfo.getDocId(), taskInfo.getNode().getId(),  nextNodes);

        for(FlowNode node: nextNodes){
            if(autoTypes.contains(node.getOperationType())){
                //使用多线程以提高并发性能
                if(flowContext.getFlowConfig().isMultiThread()) {
                    this.setTaskInfo(copyTaskInfo(taskInfo, node));
                    flowContext.getThreadPoolService().execute(this);
                }else{
                    this.execute(copyTaskInfo(taskInfo, node));
                }
            }
        }
    }


    @Override
    public boolean invokeExecutorComponent(TaskInfo taskInfo) {
        Object bean = flowContext.getExecutor(taskInfo.getFlowCode());
        Method method = flowContext.getMethod(taskInfo.getFlowCode(), taskInfo.getNode().getCode());
        if(bean != null && method != null){
            try {
                Boolean result = (Boolean) method.invoke(bean, taskInfo);
                if(result != null){
                    return result;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean executeTask(TaskInfo taskInfo) throws FlowException {

        boolean result = true;

        FlowNode node = taskInfo.getNode();

        if(OperationType.END == (node.getOperationType())){
            this.finishTask(taskInfo);
        }else{
            NodeBranchSelector nodeBranchSelector = NodeBranchSelectorFactory.createNodeBranchSelector(node.getOperationType());
            if(nodeBranchSelector == null){
                throw new FlowOperationTypeInvalidException(taskInfo);
            }
            this.autoExecute(taskInfo, nodeBranchSelector.selectNextNode(flowContext, taskInfo));
        }

        return result;
    }


    @Override
    public boolean suspendTask(TaskInfo taskInfo) throws FlowException {
        return false;
    }

    @Override
    public boolean recoveryTask(TaskInfo taskInfo) throws FlowException {
        return false;
    }

    /**
     * 节点定义的附加任务
     * @param taskInfo
     */
    @Override
    public boolean invokeNodeComponent(TaskInfo taskInfo){
        //执行用户自定义任务
        FlowNode node = taskInfo.getNode();
        if(!StringUtils.isEmpty(node.getExecutorObj())){
            try {
                TaskExecutor executor = (TaskExecutor) Class.forName(node.getExecutorObj()).newInstance();
                return executor.execute(taskInfo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }


    private TaskInfo copyTaskInfo(TaskInfo taskInfo, FlowNode nextNode){
        TaskInfo nextTaskInfo = new TaskInfo();
        BeanUtils.copyProperties(taskInfo, nextTaskInfo, "node");
        nextTaskInfo.setNode(nextNode);
        return nextTaskInfo;
    }
}
